#ifndef FONTFACE_H
#define FONTFACE_H
#include "Freetype2.h"

namespace FT
{
/**
 * @brief Class for representing TrueType font.
 */
class FontFace
{
friend class BaseGlyph;
public:
    /**
     * @brief Creates FontFace with TrueType font specified by fontPath.
     * @param fontPath path to TrueType font
     */
    FontFace(std::string fontPath) throw (ft2exception)
    {
        error = FT_New_Face(FT::FreeType2::getLibrary(),fontPath.c_str(),0,&face);
        if (error == FT_Err_Unknown_File_Format)
        {
            throw ft2exception(std::string("FT_New_Face failed with FT_Err_Unknown_File_Format"));
        }
        else if (error)
        {
            throw ft2exception(std::string("FT_New_Face failed. maybe file broken or unreadable"));
        }
        hasKerning_ = FT_HAS_KERNING(face);
    }
    /**
     * @brief Creates FontFace with TrueType font specified by fontPath and character size.
     * @param fontPath path to TrueType font
     * @param charSize character size
     */
    FontFace(std::string fontPath, int charSize) throw (ft2exception)
    {
        error = FT_New_Face(FT::FreeType2::getLibrary(),fontPath.c_str(),0,&face);
        if (error == FT_Err_Unknown_File_Format)
        {
            throw ft2exception(std::string("FT_New_Face failed with FT_Err_Unknown_File_Format"));
        }
        else if (error)
        {
            throw ft2exception(std::string("FT_New_Face failed. maybe file broken or unreadable"));
        }
        hasKerning_ = FT_HAS_KERNING(face);
        setCharSize(charSize);
    }
    /**
     * @brief Checks, if FontFace has kerning.
     * @return true, if FontFace has kerning
     */
    bool hasKerning()
    {
        return hasKerning_;
    }
    /**
     * @brief Set character size of FontFace.
     * @param charSize character size
     */
    void setCharSize(int charSize)
    {
        error = FT_Set_Char_Size(
                    face,    /* handle to face object           */
                    0,       /* char_width in 1/64th of points  */
                    charSize*64,   /* char_height in 1/64th of points */
                    300,     /* horizontal device resolution    */
                    300 );   /* vertical device resolution      */
        if (error)
        {
            throw ft2exception(std::string("FT_Set_Char_Size failed."));
        }
        this->size = charSize;
    }
    int getCharSize()
    {
        return size;
    }
    /**
     * @brief Create glyph from character codepoint. T must be derived from BaseGlyph.
     * @param codePoint character codepoint
     * @return created glyph of type T
     */
    template <class T>
    T* createGlyph(ulong codePoint)
    {
        uint glyphIndex = FT_Get_Char_Index(face, codePoint);
        error = FT_Load_Glyph( face, glyphIndex, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
        if ( error )
        {
            throw ft2exception(std::string("FT_Load_Glyph failed."));
        }
        error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
        if ( error )
        {
            throw ft2exception(std::string("FT_Render_Glyph failed."));
        }
        return new T(glyphIndex, Point(face->glyph->advance.x >> 6,face->glyph->advance.y >> 6),
                    Point(face->glyph->metrics.horiBearingX >> 6,face->glyph->metrics.horiBearingY >> 6),*this, face->glyph->bitmap);
    }

    signed long getNumGlyphs()
    {
        return face->num_glyphs;
    }

    signed long getFaceFlags()
    {
        return face->face_flags;
    }

    int getLastError()
    {
        return error;
    }
private:
    int size;
    bool hasKerning_;
    FT_Face face;
    FT_Error error;
};
}
#endif // FONTFACE_H
